<?php
/**
 * Created by PhpStorm.
 * User: Administrator
 * Date: 2019/9/25 0025
 * Time: 14:10
 */

ini_set('default_socket_timeout', -1);
include "library/mRedis.php";
include "model/Order.php";

class WorkerService {

    public $config,$redis;

    public function start(){

        $this->config = include "config/config.php";
        $this->redis = mRedis::get_instance($this->config);

        while(
            $t = $this->redis->brPop(
                $this->taskQueueKey(),0
            )
        ){


            if(count($t)){
                /*
                 * data demo
                array(2) {
                    [0]=>
  string(23) "DEMO_COMPANY-TASK-QUEUE"
                    [1]=>
  string(73) "{"uid":"vimphen","price":1,"vol":1,"act":"LONG_ACTION","time":1569
393115}"
                */

                $this->log("get data : " . json_encode($t));
                $this->task($t);

            }
        }
    }


    public function task($t){

        $data = json_decode($t[1]);

        //查找相反的仓位，使用redis速度远远大于mysql

        if($data->act == Order::LONG_ACTION || $data->act == Order::PENDING_LONG_ACTION){
            $key = $this->_queueKey($data->symbol,Order::SHORT_ACTION);
            $orders = $this->redis->zrangeByscore($key,$data->price,$data->price);
        }else{
            $key = $this->_queueKey($data->symbol,Order::LONG_ACTION);
            $orders = $this->redis->zrangeByscore($key,$data->price,$data->price);
        }

        if(count($orders) && $orders){
            //得到数据为
            /*
            array(1) {
                [0]=>
  string(90) "{"uid":"vimphen","price":10,"symbol":"USDT","vol":1,"act":"LONG_ACTION","time":1569398609}"}
            */
            //这里会出现这种情况，比如买是2个单位，卖出是1个单位的情况，也就是分仓的概念。这里做一个简单的判断。
            //如果存在，则成交，并把相关的订单从集合中删除掉

            //最新订单
            $vol_from = $data->vol;
            $opArr = array();

            foreach($orders as $order){
                $orderObj = json_decode($order);
                $vol_to = $orderObj->vol;
                //完全匹配
                if($vol_to == $vol_from){
                    $this->log("order found ,matched");
                    //todo 从集合里删除两个交易记录
                    $opArr[] = json_encode($data);
                    $this->redis->zrem($key,json_encode($data));
                    $opArr[] = $order;
                    $this->redis->zrem(
                        $this->_queueKey($orderObj->symbol,$this->getOppositeAction($data->act)),
                        $order
                    );
                    break;
                }elseif($vol_to > $vol_from){
                    //todo 从集合里删除2个记录，并重新添加一个。
                    $this->log("order found , from < to ");
                    $opArr[] = json_encode($order);
                    $this->redis->zrem($key,json_encode($data));
                    $_tmp_order = $order;
                    $_tmp_order->vol = $data->vol;
                    $opArr[] = json_encode($_tmp_order);

                    $this->redis->zrem(
                        $this->_queueKey($orderObj->symbol,$this->getOppositeAction($data->act)),
                        $order
                    );
                    $order->vol -= $vol_from;
                    $this->redis->zadd(
                        $this->_queueKey($orderObj->symbol,$this->getOppositeAction($data->act)),
                        json_encode($order)
                    );
                    break;
                }else{
                    //todo 从集合里删除一个记录，并重新添加一个。
                    $this->log("order found , from > to ");
                    $opArr[] = $order;
                    $this->redis->zrem(
                        $this->_queueKey($orderObj->symbol,$this->getOppositeAction($data->act))
                    );
                    $vol_from = $vol_from - $vol_to;
                    $_tmp_order = $data;
                    $_tmp_order->vol = $vol_to;
                    $opArr[] = json_encode($_tmp_order);

                    $this->redis->zrem(
                        $key,json_encode($data)
                    );
                    $data->vol = $vol_from;
                    $this->redis->zadd(
                        $key,json_encode($data)
                    );
                }
            }

            $this->addDb($opArr);

        }else{
            //没有相反的交易，返回订单，不做处理。
            //从当前集合里删除当前订单。
            $this->redis->zrem(
                $data->act,json_encode($data)
            );
            $this->log(
                "no order found,quit!"
            );
        }

    }

    public function addDb($arr){
        $this->log("save data to db");
        var_dump($arr);
        //todo 写到数据库，持久化存储。这个大家都会，不做了。
    }

    public function taskQueueKey(){
            return $taskListKey = strtoupper(
            sprintf(
                "%s-task-queue",$this->config->company
            )
        );
    }

    /**
     * 得到相反的集合
     * @param $action
     * @return string
     */
    public function getOppositeAction($action){
        if($action == Order::PENDING_LONG_ACTION || $action == Order::LONG_ACTION){
            return Order::SHORT_ACTION;
        }else{
            return Order::LONG_ACTION;
        }
    }

    /**
     * 格式化序列KEY
     * @param $symbol
     * @param $action
     * @return string
     */
    public function _queueKey($symbol,$action){
        return strtoupper(sprintf("%s-%s-QUEUE",$symbol,$action));
    }

    public function log($msg){
        echo microtime(true) . ":" . $msg . PHP_EOL;
    }

}

(new WorkerService())->start();